﻿using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Mysoft.App.Appservices.Basic;
using Mysoft.Common.Configuration;
using Mysoft.Common.Extensions;
using Mysoft.Common.Jwt;
using Mysoft.Common.Model;
using Mysoft.Common.Response;
using Mysoft.Data;
using Mysoft.Data.UserManager;
using Mysoft.Domain;
using Mysoft.Domain.Basic;
using Mysoft.Dto;
using Mysoft.Entity;
using System.Collections.Concurrent;

namespace Mysoft.App.Appservices
{
    /// <summary>
    /// 用户应用服务
    /// </summary>
    public class UserAppService : AppServiceBase
    {
        private readonly DomainService<UserDomainService> _domainService;
        private readonly EntityService<Sys_User> _entityService;
        private readonly IMapper _mapper;
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="domainService"></param>
        public UserAppService(DomainService<UserDomainService> domainService, IMapper mapper, EntityService<Sys_User> entityService)
        {
            _domainService = domainService;
            _mapper = mapper;
            _entityService = entityService;
        }

         /// <summary>
         /// 登录
         /// </summary>
         /// <param name="login"></param>
         /// <returns></returns>
        [HttpPost, AllowAnonymous]
        public async Task<JsonResult> SignIn(UserSignIn login)
        {
            var user = _domainService.Instance.Login(login.UserName, login.Password);
            if (user == null)
            {
                base.BusinessException("用户名或密码错误");
            }

            string token = JwtHelper.IssueJwt(new Common.Model.UserInfo
            {
                Id = user.Id,
                Name = user.Name
            });
            _domainService.Instance.ChangeToken(user.Id, token);
            UserContext.Current.LogOut(user.Id);
            //var dto = _mapper.Map<UserDto>(user);
            //dto.Password = null;
            return Success(token);
        }
        /// <summary>
        /// 获取当前登录的用户
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public JsonResult GetUser()
        {
            var dto = _domainService.Instance.GetUser();
           return Success(dto);
        }
        /// <summary>
        /// 退出登录
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        [HttpPost]
        public JsonResult SignOut(Guid? Id)
        {
            if (!Id.HasValue || Id == Guid.Empty) 
            {
                BusinessException(nameof(Id));
            }
            _UserContext.LogOut(Id.Value);
            return Success("注销成功");
        }

        private readonly ConcurrentDictionary<Guid, object> _lockCurrent = new ConcurrentDictionary<Guid, object>();
        /// <summary>
        /// 刷新token
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public JsonResult ReplaceToken()
        {
            ResponseContent rc = new ResponseContent();
            string error = "";
            string key = $"rp:Token:{UserContext.Current.UserId}";
            UserInfo userInfo = null;
            try
            {
                //如果5秒内替换过token,直接使用最新的token(防止一个页面多个并发请求同时替换token导致token错位)
                if (_CacheContext.Exists(key))
                {
                    return Json(Response(rc,_CacheContext.Get(key), true)); 
                }
                var _obj = _lockCurrent.GetOrAdd(_UserContext.UserInfo.Id.Value, new object() { });
                lock (_obj)
                {
                    if (_CacheContext.Exists(key))
                    {
                        return Json(Response(rc, _CacheContext.Get(key), true));
                    }
                    string requestToken = HttpContext.Request.Headers[AppSetting.TokenHeaderName];
                    requestToken = requestToken?.Replace("Bearer ", "");

                    if (JwtHelper.IsExp(requestToken)) return Json(Response(rc, "Token已过期", false));

                    Guid userId = _UserContext.UserInfo.Id.Value;

                    userInfo = _entityService.Instance.FindAsNoTracking(x => x.Id == userId).Select(
                             s => new UserInfo()
                             {
                                 Id = userId,
                                 Name = s.Name
                             }).FirstOrDefault();

                    if (userInfo == null) return Json(Response(rc, "未查到用户信息", false));

                    string token = JwtHelper.IssueJwt(userInfo);
                    //移除当前缓存
                    _CacheContext.Remove(userId.GetUserKey());
                    //只更新的token字段
                    //_userRepository.Update(new Sys_User() { User_Id = userId, Token = token }, x => x.Token, true);
                     _domainService.Instance.ChangeToken(userId, token);
                    //添加一个5秒缓存
                    _CacheContext.Add(key, token, 5);
                    return Json(Response(rc, token, true));
                }
            }
            catch (Exception ex)
            {
                error = ex.Message + ex.StackTrace;
                Response(rc, "token替换异常", false);
            }
            finally
            {
                _lockCurrent.TryRemove(_UserContext.UserInfo.Id.Value, out object val);
            }
            return Json(rc);
        }
    }
}
